package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.enums.HttpCodeEnum;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.WmNewsAuthDto;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.dto.WmNewsPageReqDto;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.mapper.WmUserMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.pojo.WmUser;
import com.itheima.wemedia.service.WmNewsService;
import com.itheima.wemedia.service.WmUserService;
import com.itheima.wemedia.vo.WmNewsVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @description <p>自媒体图文内容信息 业务实现</p>
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Autowired
    private WmUserMapper wmUserMapper;


    /**
     * 自媒体文章分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo<WmNews> findPage(WmNewsPageReqDto dto) {
        //获取分页数据，设置分页参数
        IPage<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //构建条件构造器
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        //设置条件
        lqw.eq(null != dto.getStatus(), WmNews::getStatus, dto.getStatus())
                .like(null != dto.getKeyword(), WmNews::getTitle, dto.getKeyword())
                .eq(null != dto.getChannelId(), WmNews::getChannelId, dto.getChannelId())
                //ge大于等于，gt大于
                .ge(null != dto.getBeginPubDate(), WmNews::getPublishTime, dto.getBeginPubDate())
                //le小于等于，lt小于
                .lt(null != dto.getEndPubDate(), WmNews::getPublishTime, dto.getEndPubDate())
                .orderByDesc(WmNews::getCreatedTime);
        //查询
        page(pageInfo, lqw);
        //构建分页结果返回
        return PageResultVo.pageResult(dto.getPage(), dto.getSize(),
                pageInfo.getTotal(), pageInfo.getRecords());
    }

    /**
     * 提交文章
     *
     * @param draft
     * @param dtoSave
     * @return
     */
    @Override
    @Transactional
    public Integer submit(WmNewsDtoSave dtoSave, boolean draft) {
        //创建list集合存储图片
        //存储封面图片的集合
        List<String> coverImgList = new ArrayList<>();
        //存储内容图片的集合
        List<String> contentImgList = new ArrayList<>();

        //对前端的参数进行校验
        String content = dtoSave.getContent();
        if (StringUtils.isEmpty(dtoSave) || StringUtils.isEmpty(content)) {
            throw new LeadNewsException("文章内容不能为空！");
        }
        //创建文章对象
        WmNews pojo = new WmNews();

        //赋值对象中的属性
        BeanUtils.copyProperties(dtoSave, pojo);

        //判断是否有发布时间-如果没有，就设置当前时间
        if (null == pojo.getPublishTime()) {
            pojo.setPublishTime(LocalDateTime.now());
        }

        //设置参数
        pojo.setUserId(Long.parseLong(RequestContextUtil.getUserId()));
        pojo.setCreatedTime(LocalDateTime.now());
        pojo.setSubmitedTime(LocalDateTime.now());

        //判断是否为草稿--设置状态
        pojo.setStatus(draft ? BusinessConstants.WmNewsConstants.STATUS_DRAFT :
                BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
        //刚创建的文章，还未上架
        pojo.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);

        //文章封面，如果是自动，dto提供的images可能为空
        if (CollectionUtils.isNotEmpty(dtoSave.getImages())) {
            //图片为多图时，存入数据库以逗号分隔
            String images = String.join(",", dtoSave.getImages());
            pojo.setImages(images);
            //批量添加封面图片进集合
            coverImgList.addAll(dtoSave.getImages());
        }
        //从文章内容中抽取图片作为封面
        List<WmNewsContentNodeDto> contentNodeDtoList = JSON.parseArray(content, WmNewsContentNodeDto.class);
        //遍历集合后添加进内容集合中--使用stream流或者for循环
        //遍历每一张图片--for循环
        /*for (WmNewsContentNodeDto nodeDto : contentNodeDtoList) {
            //判断数据是否正确
            if(BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(nodeDto.getType())){
                String imageUrl = nodeDto.getValue();
                //将图片加入集合中
                contentImgList.add(imageUrl);
            }

        }*/
        //遍历每一张图片--stream流
        contentImgList = contentNodeDtoList.stream()
                .filter(nodeDto ->
                        BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(nodeDto.getType())
                ).map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());

        //判断封面类型是否为自动
        if (dtoSave.getType() == BusinessConstants.WmNewsConstants.TYPE_AUTO) {
            //判断图片数量，设置封面布局
            int size = contentImgList.size();
            //size=0--文章中无图-type=0
            if (size == 0) {
                pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
                pojo.setImages("");
            } else if (size <= 2) {
                //图片小于等于两张-type=1
                pojo.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG);
                //设置数组中第一张图片为封面
                pojo.setImages(contentImgList.get(0));
                coverImgList.add(contentImgList.get(0));
            } else {
                //图片超过两张-type=3
                pojo.setType(BusinessConstants.WmNewsConstants.TYPE_MULTIPLE_IMG);
                String images = contentImgList.stream().limit(3).collect(Collectors.joining(","));

                //设置封面图片
                pojo.setImages(images);
            }
        }

        //保存文章
        //判断是否有id有就更新，没有新增
        //状态为草稿的也新增--保留草稿
        if (null == dtoSave.getId() || dtoSave.getStatus().equals(BusinessConstants.WmNewsConstants.STATUS_DRAFT)) {
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_DRAFT);
            save(pojo);
        } else {
            //更新操作
            pojo.setId(dtoSave.getId());
            updateById(pojo);
        }
        //添加文章与素材之间的关系
        addRelationship(pojo.getId(), coverImgList, contentImgList);

        //文章自动审核处理
        if (pojo.getStatus() == BusinessConstants.WmNewsConstants.STATUS_SUBMIT) {
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_AUTO_SCAN_TOPIC,
                    pojo.getId().toString());
        }
        return pojo.getId().intValue();
    }

    /**
     * 删除文章
     * 文章状态status为9，且已上架的enable为1的不能删除
     *
     * @param newsId
     * @return
     */
    @Override
    public Boolean deleteById(Integer newsId) {
        //通过id查询
        WmNews wmNews = getById(newsId);
        if (wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_PUBLISHED
                && wmNews.getEnable() == BusinessConstants.WmNewsConstants.ENABLE_ON) {
            throw new LeadNewsException("文章已通过审核发布或已上架，禁止删除！");
        }
        //否则直接删除
        //removeById(newsId); --删除文章时，需要发送消息队列给kafka修改文章配置表的is_delete字段
        if(removeById(newsId)){
            //构建一个map集合存入传递的参数
            Map<String, Object> msgMap = new HashMap<>();
            msgMap.put("articleId",wmNews.getArticleId());
            //为1代表已删除
            msgMap.put("isDelete",1);
            //发送消息到kafka
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_IS_DELETE_TOPIC,JSON.toJSONString(msgMap));
        }
        //删除关系表数据
        removeRelationship(newsId);
        return true;
    }

    /**
     * 上架或者下架
     *
     * @param paramMap
     */
    @Override
    public void downOrUp(Map<String, Integer> paramMap) {
        //获取参数后对参数进行校验
        Integer id = paramMap.get("id");
        Integer enable = paramMap.get("enable");
        //参数校验
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(enable)
                || enable < 0 || enable > 1) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_INVALID);
        }
        //通过id查询数据库
        WmNews wmNews = getById(id);
        //只有文章已发布才可以做上架下架
        if (wmNews.getStatus() != BusinessConstants.WmNewsConstants.STATUS_PUBLISHED) {
            throw new LeadNewsException("文章尚未发布，无法上下架！");
        }
        WmNews wmNews1 = new WmNews();
        wmNews1.setId(id.longValue());
        //判断传过来的enable值--上架或下架
        //如果为0-下架
        if (enable == BusinessConstants.WmNewsConstants.ENABLE_OFF) {
            wmNews1.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);
            wmNews1.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);

        } else {
            wmNews1.setEnable(BusinessConstants.WmNewsConstants.ENABLE_ON);
        }
        wmNews1.setSubmitedTime(LocalDateTime.now());
        //更新数据库
        //updateById(wmNews1); --修改上下架时同步文章微服务数据
        if (updateById(wmNews1)) {
            Map<String, Object> msgMap = new HashMap<>();
            msgMap.put("articleId", wmNews.getArticleId());
            //三元表达式判断enable状态等于
            msgMap.put("enable", wmNews1.getEnable() == 0 ? 1 : 0);

            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_DOWN_OR_UP_TOPIC,JSON.toJSONString(msgMap));
        }
    }

    /**
     * 通过作者名称分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo<WmNewsVo> findPageByAuthorName(WmNewsPageReqDto dto) {
        //设置分页参数
        IPage<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //构建查询条件
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        //设置条件
        lqw.eq(null != dto.getStatus(), WmNews::getStatus, dto.getStatus());
        lqw.like(null != dto.getTitle(), WmNews::getTitle, dto.getTitle());

        //查询
        page(pageInfo, lqw);
        //获取查询结果
        List<WmNewsVo> wmNewsVoList = new ArrayList<>();
        List<WmNews> wmNewsList = pageInfo.getRecords();
        if (!StringUtils.isEmpty(wmNewsList)) {
            //构造WmNewsVo
            List<Long> userIdList = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());

            //获取作者名称
            //通过userId批量查询wmUser表，获取名称
            List<WmUser> wmUserList = wmUserMapper.selectBatchIds(userIdList);
            //将自媒体用户取出名称，创建成map集合
            Map<Long, WmUser> authorNameMap = wmUserList.stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));
            //转换成WmNewsVo
            wmNewsVoList = wmNewsList.stream().map(s ->
                    WmNewsVo.build(s, authorNameMap.get(s.getUserId()))
            ).collect(Collectors.toList());
        }

        return PageResultVo.pageResult(dto.getPage(), dto.getSize(),
                pageInfo.getTotal(), wmNewsVoList);
    }

    /**
     * 审核通过
     *
     * @param dto
     */
    @Override
    public void authPass(WmNewsAuthDto dto) {
        //校验参数--通过id查询数据库，看是否有此文章
        Long id = dto.getId();
        WmNews wmNews = getById(id);
        if (null != wmNews) {
            WmNews updatePojo = new WmNews();
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
            updatePojo.setId(id);
            updateById(updatePojo);
        }

    }

    /**
     * 审核失败
     *
     * @param dto
     */
    @Override
    public void authFail(WmNewsAuthDto dto) {
        //获取参数并校验
        Long id = dto.getId();
        String msg = dto.getMsg();
        if (null != id && null != msg) {
            WmNews wmNews = getById(id);
            if (!StringUtils.isEmpty(wmNews)) {
                WmNews updatePojo = new WmNews();
                updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
                updatePojo.setId(id);
                updatePojo.setReason(msg);

                updateById(updatePojo);
            }
        }
    }

    @Override
    public WmNewsVo getOneVo(Long newsId) {
        WmNews wmNews = getById(newsId);
        Long userId = wmNews.getUserId();
        WmUser wmUser = wmUserMapper.selectById(userId);

        WmNewsVo wmNewsVo = WmNewsVo.build(wmNews, wmUser);
        return wmNewsVo;
    }

    /**
     * 查询审核通过的文章，状态为8。进行数据同步到文章微服务
     *
     * @param dto
     * @return
     */
    @Override
    public List<WmNewsVo> listArticleSync(WmNewsPageReqDto dto) {
        //构建条件status=8,4
        //查询，得到数据列表
        //构建发布时间条件
        List<WmNews> wmNewsList = query()
                .in("status", BusinessConstants.WmNewsConstants.STATUS_PASS,
                        BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS)
                .le(null != dto.getEndPubDate(), "publish_time", dto.getEndPubDate())
                .list();
        //获取所有作者的id
        List<WmNewsVo> voList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(wmNewsList)) {
            //自媒体账号id
            List<Long> wmUserIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //批量查询wm_user表，ap_user_id作者id，name=作者名称
            List<WmUser> wmUserList = wmUserMapper.selectBatchIds(wmUserIds);
            //map<userId,WmUser>
            Map<Long, WmUser> wmUserMap = wmUserList.stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));

            //将map中的对象转成wmNewsVo
            voList = wmNewsList.stream().map(wmNews ->
                    WmNewsVo.build(wmNews, wmUserMap.get(wmNews.getUserId()))).collect(Collectors.toList());
        }
        return voList;
    }

    /**
     * 删除关系表
     *
     * @param newsId
     */
    private void removeRelationship(Integer newsId) {
        LambdaQueryWrapper<WmNewsMaterial> lqw = Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, newsId);
        //批量删除
        wmNewsMaterialMapper.delete(lqw);
    }

    /**
     * 添加文章与素材之间的关系
     *
     * @param id
     * @param coverImgList
     * @param contentImgList
     */
    private void addRelationship(Long id, List<String> coverImgList, List<String> contentImgList) {
        //使用set集合合并图片，起到去重的效果
        Set<String> allImages = new HashSet<>();
        if (CollectionUtils.isNotEmpty(coverImgList)) {
            //去除每张图片的前缀，加入集合中
            coverImgList = coverImgList.stream()
                    .map(this::removePrefix).collect(Collectors.toList());
            allImages.addAll(coverImgList);
        }
        //内容中图片做同样处理
        if (CollectionUtils.isNotEmpty(contentImgList)) {
            contentImgList = contentImgList.stream()
                    .map(this::removePrefix).collect(Collectors.toList());
            allImages.addAll(contentImgList);
        }

        //判断集合中数据是否为空
        if (CollectionUtils.isNotEmpty(allImages)) {
            LambdaQueryWrapper<WmMaterial> lqw = Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, allImages);

            //批量查询
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(lqw);
            //判断素材是否不存在或者缺少
            if (null == wmMaterials || wmMaterials.size() != allImages.size()) {
                throw new LeadNewsException("文章素材缺失！");
            }

            //添加文章与素材关系
            Map<String, Long> urlIdMap = wmMaterials.stream()
                    .collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
            //通过遍历封面集合中的url去map集合中取值
            if (CollectionUtils.isNotEmpty(coverImgList)) {
                for (String url : coverImgList) {
                    //通过url查找map中的值
                    Long materialId = urlIdMap.get(url);
                    //创建对象设置参数
                    WmNewsMaterial newsMaterial = new WmNewsMaterial();
                    newsMaterial.setMaterialId(materialId);
                    newsMaterial.setNewsId(id);
                    newsMaterial.setType(BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);

                    //保存数据
                    wmNewsMaterialMapper.insert(newsMaterial);
                }
            }
            //内容中的图片也转成对象
            if (CollectionUtils.isNotEmpty(contentImgList)) {
                for (String url : contentImgList) {
                    //通过url查找map中的值
                    Long materialId = urlIdMap.get(url);
                    //创建对象设置参数
                    WmNewsMaterial newsMaterial = new WmNewsMaterial();
                    newsMaterial.setMaterialId(materialId);
                    newsMaterial.setNewsId(id);
                    newsMaterial.setType(BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);

                    //保存数据
                    wmNewsMaterialMapper.insert(newsMaterial);
                }
            }
        }
    }

    private String removePrefix(String url) {
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }
}
